﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Resources;
using System.Collections;
using System.Diagnostics.Contracts;
using YasharEl.Infrastructure.ResourcesManagement.Configuration;

namespace YasharEl.Infrastructure.ResourcesManagement.Managers.Database
{
    /// <summary>
    /// Custom resource manager for managing resources held on a database
    /// </summary>
    public class DataResourceManager : ExtendedComponentResourceManager
    {
        #region Fields
        private DataProvider dataProvider;
        private string connectionString;
        private string baseName;
        #endregion

        #region Construction

        /// <summary>
        /// Initializes a new instance of the <see cref="DataResourceManager"/> class.
        /// </summary>
        /// <param name="database">The database.</param>
        /// <param name="baseName">base name for the set of resources.</param>
        public DataResourceManager(DataProvider dataProvider, string connectionString, string baseName)
        {
            Initialize(dataProvider, connectionString, baseName);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DataResourceManager"/> class.
        /// </summary>
        /// <param name="database">The database.</param>
        /// <param name="resourceType">Type of the resource.</param>
        public DataResourceManager(DataProvider dataProvider, string connectionString, Type resourceType)
        {
            Contract.Requires<ArgumentNullException>(resourceType != null, "resourceType could not be null.");

            Initialize(dataProvider, connectionString, resourceType.FullNameToString());
        }

        #endregion

        #region Protected Methods
        /// <summary>
        /// Initializes the data resource manager.
        /// </summary>
        /// <param name="databaseInstance">The database instance.</param>
        /// <param name="resourceBaseName">Name of the resource base.</param>
        protected void Initialize(DataProvider dataProvider, string connectionString, string resourceBaseName)
        {
            this.dataProvider = dataProvider;
            this.connectionString = connectionString;
            this.baseName = resourceBaseName;
            this.ResourceSets = new Hashtable();
        }

        /// <summary>
        /// Provides the implementation for finding a <see cref="T:System.Resources.ResourceSet"></see>.
        /// </summary>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"></see> to look for.</param>
        /// <param name="createIfNotExists">If true and if the <see cref="T:System.Resources.ResourceSet"></see> has not been loaded yet, load it.</param>
        /// <param name="tryParents">If the <see cref="T:System.Resources.ResourceSet"></see> cannot be loaded, try parent <see cref="T:System.Globalization.CultureInfo"></see> objects to see if they exist.</param>
        /// <returns>
        /// The specified <see cref="T:System.Resources.ResourceSet"></see>.
        /// </returns>
        /// <exception cref="T:System.Resources.MissingManifestResourceException">The database contains no resources or fallback resources for the culture given and it is required to look up a resource. </exception>
        protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
        {
            DataResourceSet resourceSet = null;

            // check the resource set cache first
            if (ResourceSets.Contains(culture.Name))
                resourceSet = (DataResourceSet)ResourceSets[culture.Name];
            else
            {
                // create a new resource set
                resourceSet = new DataResourceSet(dataProvider, connectionString, baseName, culture);
                // check the number of resources returned
                if (resourceSet.Count == 0)
                {
                    // try the parent culture if not already at the invariant culture
                    if (tryParents)
                    {
                        if (!culture.Equals(CultureInfo.InvariantCulture))
                            // do a recursive call on this method with the parent culture
                            resourceSet = this.InternalGetResourceSet(culture.Parent, createIfNotExists, tryParents) as DataResourceSet;
                    }
                }
                else
                {
                    // only cache the resource if the createIfNotExists flag is set
                    if (createIfNotExists)
                        ResourceSets.Add(culture.Name, resourceSet);
                }
            }
            return resourceSet;
        }
        #endregion
    }
}
